<?php
/**
 * @link https://www.len168.com
 * @copyright Copyright (c) 2020/9/21 len168.com
 * @author toshcn <toshcn@foxmail.com>
 */
namespace common\models;

use Yii;

/**
 * Login form
 */
class LoginForm extends BaseModel
{
    public $username;
    public $password;
    public $unionid; //第三方登录唯一id
    /** @var string 登录类型: pwd(用户名+密码登录), captcha(手机+验证码登录) weixin微信 alipay支付宝 */
    public $type;
    /** @var integer 手机号国家代码: 86(中国) */
    public $countryCode;
    /** @var string 验证码 */
    public $captcha;
    /**
     * @var string 验证码类型 local系统验证码，sms短信
     */
    public $captchaType;

    private $_user;

    /**
     * 场景
     * @return array
     */
    public function scenarios()
    {
        $scenarios = parent::scenarios();
        $scenarios['pwd_login'] = ['username', 'type', 'password'];
        $scenarios['captcha_login'] = ['username', 'type', 'countryCode', 'captcha', 'captchaType'];
        $scenarios['oauth_login'] = ['unionid', 'type'];
        $scenarios['admin_login'] = ['username', 'type', 'password', 'captcha', 'captchaType'];
        return $scenarios;
    }

    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            [['username', 'unionid', 'type', 'password', 'captcha'], 'trim'],
            // username and password are both required
            [['password'], 'required', 'on' => ['pwd_login', 'admin_login']],
            [['username', 'type'], 'required', 'on' => ['pwd_login', 'captcha_login', 'admin_login']],
            [['unionid', 'type'], 'required', 'on' => 'oauth_login'],
            [['type'], 'in', 'range' => ['pwd', 'captcha', 'weixin', 'alipay', 'admin']],
            ['captcha', 'validateCaptcha', 'params' => ['mobile' => $this->countryCode . $this->username], 'on' => ['captcha_login', 'admin_login']],
            // password is validated by validatePassword()
            ['password', 'validatePassword', 'on' => ['pwd_login', 'admin_login']]
        ];
    }

    /**
     * 密码验证
     *
     * @param string $attribute the attribute currently being validated
     * @param array $params the additional name-value pairs given in the rule
     */
    public function validatePassword($attribute, $params)
    {
        if (!$this->hasErrors()) {
            if ($user = $this->getUser()) {
                $sec = (int) Yii::$app->getCache()->get(Yii::$app->util->cacheKey('user.loginPasswordError.' . $user->id));
                $errors = (int) Yii::$app->config->getUserItem('loginPasswordError');
                if ($sec && $errors > 0 && $user->password_error >= $errors) {
                    // 缓存下次可登录时间 最长10分钟
                    $sec += 30;
                    $sec = $sec > 600 ? 600 : $sec;

                    Yii::$app->getCache()->set(Yii::$app->util->cacheKey('user.loginPasswordError.' . $user->id), $sec, $sec);
                    $this->addError($attribute, '密码错误次数太多，请' . $sec . '秒后再试');
                }
            }

            if (empty($this->$attribute) || !$user || !$user->validatePassword($this->$attribute)) {
                // 密码错误
                if ($user) {//密码错误次数加一
                    $user->loginPasswordError();
                }
                $this->addError($attribute, Yii::t('common', 'Incorrect username or password.'));
            }
        }
    }

    /**
     * 验证码验证
     * @param string $attribute the attribute currently being validated
     * @param array $params the additional name-value pairs given in the rule
     * @return void
     */
    public function validateCaptcha($attribute, $params)
    {
        if (!$this->hasErrors()) {
            if ($this->captchaType === 'local') {
                // 使用本地系统验证码
                if (!Yii::$app->controller->createAction('captcha')->validate($this->$attribute, Yii::$app->config->getSiteItem('captchaCaseSensitive'))) {
                    $this->addError($attribute, '图形验证码不正确');
                }
            } else {
                // 使用短信验证码
                if (!Yii::$app->sms->validateCaptcha($this->$attribute, $params['mobile'], SmsCaptchaForm::LABEL_LOGIN)) {
                    $this->addError($attribute, '短信验证码不正确');
                }
            }
        }
    }

    /**
     * 登录
     *
     * @return bool
     * @throws \Throwable
     */
    public function login()
    {
        if ($this->validate()) {
            if ($this->getUser()) {
                if (Yii::$app->getUser()->login($this->_user)) {
                    return true;
                }
            }
            $this->addError('error', '账号不存在');
            return false;
        }
        return false;
    }

    /**
     * 第三方登录.
     *
     * @return bool
     * @throws \Throwable
     */
    public function oauthLogin()
    {
        if ($this->getUser()) {
            if (Yii::$app->getUser()->login($this->_user)) {
                return true;
            }
            $this->addError('oauth', '登录失败');
            return false;
        }
        $this->addError('oauth', '未绑定账号，请先绑定。');
        return false;
    }

    /**
     * 后台管理员登录
     *
     * @return bool
     * @throws \Throwable
     */
    public function adminLogin()
    {
        if ($this->getUser()) {
            if (Yii::$app->getUser()->login($this->_user)) {
                if (empty($this->_user->group_id)) {
                    $this->addError('group', '账号不存在或不是管理员');
                    return false;
                }
                return true;
            }
        }
        return false;
    }

    /**
     * Finds user by [mobile]
     *
     * @return User|null
     */
    protected function getUser()
    {
        if ($this->_user === null) {
            if ($this->type == 'pwd' || $this->type == 'admin') {
                if ($this->_user = User::findByUsername($this->username)) {
                    $this->_user->login_type = User::LOGIN_TYPE_PWD;
                }
            } else if ($this->type == 'captcha') {
                if ($this->_user = User::findByMobile($this->countryCode, $this->username)) {
                    $this->_user->login_type = User::LOGIN_TYPE_CAPTCHA;
                }
            } else if ($this->type == 'weixin') {
                if ($oauth = UserOauth::findOne(['unionid' => $this->unionid, 'oauth_type' => UserOauth::OAUTH_TYPE_WEIXIN])) {
                    if ($this->_user = $oauth->user) {
                        $this->_user->login_type = User::LOGIN_TYPE_WEIXIN;
                    }
                }
            } else if ($this->type == 'alipay') {
                if ($oauth = UserOauth::findOne(['unionid' => $this->unionid, 'oauth_type' => UserOauth::OAUTH_TYPE_ALIPAY])) {
                    if ($this->_user = $oauth->user) {
                        $this->_user->login_type = User::LOGIN_TYPE_ALIPAY;
                    }
                }
            }
        }
        return $this->_user;
    }

    /**
     * 后台管理员登录返回数据
     * @return array
     * @throws \Throwable
     */
    public function rebackAdminInfo()
    {
        $data = $this->_user->getCurrentAdminInfo();
        try {
            $auth = Yii::$app->getAuthManager();
            $data['menus'] = [];
            $roles = $auth->getRolesByUser($data['uid']);// 授权的全部角色
            $arr = [];
            foreach ($roles as $role) {
                $arr[] = $role->name;
            }
            $menus = MenuRole::findAllByRoleWithMenu($arr);
            foreach ($menus as $menu) {//菜单路由
                $data['menus'][] = $menu->menu->route;
            }
        } catch (\Exception $e) {
            $data['menus'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 前台用户登录返回数据
     * @return array
     * @throws \Throwable
     */
    public function rebackUserInfo()
    {
        return $this->_user->getCurrentUserInfo();
    }
}
